const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/
// 属性
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
const dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
// 标签名
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeRegExp.source}]*`
// 作用域 <span: xx>
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
// 开头标签
const startTagOpen = new RegExp(`^<${qnameCapture}`)
const startTagClose = /^\s*(\/?)>/
// 结束标签
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)
const doctype = /^<!DOCTYPE [^>]+>/i
// #7298: escape - to avoid being passed as HTML comment when inlined in page
const comment = /^<!\--/
const conditionalComment = /^<!\[/


function createASTElement(tag, attrs){
  return {
    tag,
    attrs,
    children: [], // 子节点
    type: 1,
    parent: null
  }
}
let root; // 根元素
let createParent; // 当前元素的父元素
// 数据结构  栈
let stack = [];
function start(tag, attrs){
  let element = createASTElement(tag, attrs);
  if (!root) {
    root = element;
  }
  createParent = element;
  stack.push(element);
}
function charts(text){ // 获取文本
  // 空格
  text = text.replace(/\s/g, '')
  if (text) {
    createParent.children.push({
      type: 3, // 文本
      text
    })
  }
}
function end(tag){ // 结束标签
  let element = stack.pop();
  createParent = stack[stack.length - 1];
  if (createParent) { // 元素闭合
    element.parent = createParent.tag;
    createParent.children.push(element)
  }
}
export function parseHTML(html){
  // 当html为空时结束
  while(html) {
    // 判断标签
    let textEnd = html.indexOf('<');
    if (textEnd === 0) {
      // 开始标签
      const startTagMatch = parseStartTag() // 开始标签的内容
      if (startTagMatch) {
        start(startTagMatch.tagName, startTagMatch.attrs);
        continue;
      }
      // 结束标签
      let endTagMatch = html.match(endTag);
      if (endTagMatch) {
        advance(endTagMatch[0].length);
        end(endTagMatch[1]);
        continue;
      }
    }
    // 文本
    if (textEnd > 0){
      // 获取文本内容
      let text = html.substring(0, textEnd);
      if (text) {
        advance(text.length);
        charts(text);
      }
    }
  }
  function parseStartTag(){
    const start = html.match(startTagOpen);
    if (!start) {
      return;
    }
    let match = {
      tagName: start[1],
      attrs: []
    }
    // 删除开始标签
    advance(start[0].length)
    // 属性
    let attr;
    let end;
    while(!(end = html.match(startTagClose)) && (attr = html.match(attribute))){
      match.attrs.push({
        name: attr[1],
        value: attr[3] || attr[4] || attr[5]
      })
      advance(attr[0].length)
    }
    if (end) {
      advance(end[0].length)
      return match
    }
  }
  
  function advance(n){
    html = html.substring(n)
  }
  return root;
}